/* eslint-disable prefer-promise-reject-errors */
/* eslint-disable no-param-reassign */
import Taro, { request, getStorageSync } from '@tarojs/taro';
import { Request } from '@bingo/request';
import serverRoot from '@/config/server';
import { responeStatus, deleteEmptyParams, defaultReqParams } from './constants';
import { serverUpdaingMiddleware, dataFormatMiddleware } from './responseMiddleware';
import { checkIsPauseStatus } from './requestMiddleware';
import { remindUserMiddleware, mustLoginCode } from './catchMiddleware';
import { IRequestOptions } from './IRequest';
import requestLoading from './request-loading';

const { startLoading, closeLoading, toastWithCallBack } = requestLoading;

class AppRequest extends Request {
  static requestPause = Promise.resolve();

  static requestContinue: any = null;

  // 暂停请求
  static setRequestPause = () => {
    AppRequest.requestPause = new Promise((resolve) => {
      AppRequest.requestContinue = resolve;
    });
  };

  // 恢复请求
  static setRequestContinue = () => {
    typeof AppRequest.requestContinue === 'function' && AppRequest.requestContinue();
    AppRequest.requestContinue = null;
  };
}

const serverErrorRemind = '网络连接错误，请稍后再试';

// 设置身份header
const setIdentifyHeader = () => {
  const userInfo = getStorageSync('user') || {};
  const { token, sid } = userInfo;
  if (token && sid) {
    return { token, sid };
  }
  return false;
};

let http: any = null;

const httpRequest = (options?: IRequestOptions) => {
  const mergeOptions = { ...defaultReqParams, ...(options || {}) };
  const { showLoading, deleteEmptyParam } = mergeOptions;
  // 请求核心方法
  const requestCore = (config) => {
    showLoading && startLoading();
    config.header = config.headers;
    config.url = /http/.test(config.url) ? config.url : `${serverRoot[process.env.UMI_ENV]}${config.url}`;
    // 删除空值
    deleteEmptyParam && (config.data = deleteEmptyParams(config.data));
    const header = setIdentifyHeader();
    if (header) {
      config.header = { ...config.header, ...header, bg_apple_version: process.env.VERSION };
    }

    return new Promise((resolve, reject) => {
      request({
        ...config,
        timeout: 30000, // 默认30s超时
        success: async (result) => {
          showLoading && (await closeLoading());
          const { statusCode, data } = result;
          if (statusCode >= 400 || statusCode >= 500) {
            Taro.sentry.reportRequestFail(
              {
                title: `[${statusCode}] 服务端响应异常: ${serverErrorRemind}`,
                requestOptions: config,
              },
              'error'
            );
            return reject(result);
          }
          if (mustLoginCode.includes(String(data.errorCode))) {
            Taro.sentry.reportRequestFail({
              title: `[${data.errorCode}] 服务端返回错误: ${data.errorMsg}`,
              requestOptions: config,
            });
            return reject(result);
          }
          if (data.status === responeStatus.ERROR) {
            toastWithCallBack(
              {
                title: data.errorMsg || '网络连接错误, 请稍后重试',
              },
              reject,
              { ...mergeOptions, ...result }
            );
            Taro.sentry.reportRequestFail({
              title: `[${data.errorCode}] 服务端返回错误: ${data.errorMsg}`,
              requestOptions: config,
            });
            return false;
          }
          return resolve(result);
        },
        fail: async (err) => {
          showLoading && (await closeLoading());
          toastWithCallBack(
            {
              title: '网络连接错误, 请稍后重试',
            },
            reject,
            { ...mergeOptions, ...err }
          );
          Taro.sentry.reportRequestFail(
            {
              title: `接口调用失败: ${JSON.stringify(err)}`,
              requestOptions: config,
            },
            'error'
          );
        },
      });
    });
  };

  if (!http) {
    // @ts-ignore
    http = new AppRequest(requestCore);
  }

  // request中间件
  http.useRequestMiddleware([checkIsPauseStatus]);
  // response中间件
  http.useResponseMiddleware([serverUpdaingMiddleware, dataFormatMiddleware]);
  // error catch中间件
  http.useCatchMiddleware([remindUserMiddleware]);

  return http;
};

const httpGet = (url: string, params: any, options?: IRequestOptions) => httpRequest(options).get(url, params, options);

const httpPost = (url: string, params: any, options?: IRequestOptions) =>
  httpRequest(options).post(url, params, options);

export { httpGet as get, httpPost as post };
export const requestContinue = AppRequest.setRequestContinue;
export const requestPause = AppRequest.setRequestPause;
export const isRequestPause = AppRequest.requestPause;
export const AppRequestClass = AppRequest;
